package com.wydpp.gb28181.processor.request.impl;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.wydpp.gb28181.bean.SendRtpItem;
import com.wydpp.gb28181.bean.SipDevice;
import com.wydpp.gb28181.bean.SipPlatform;
import com.wydpp.gb28181.commander.SIPCommander;
import com.wydpp.gb28181.event.SipSubscribe;
import com.wydpp.gb28181.processor.SIPProcessorObserver;
import com.wydpp.gb28181.processor.request.ISIPRequestProcessor;
import com.wydpp.gb28181.processor.request.SIPRequestProcessorParent;
import com.wydpp.utils.HttpUtil;
import com.wydpp.xml.xml;
import gov.nist.javax.sdp.TimeDescriptionImpl;
import gov.nist.javax.sdp.fields.TimeField;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import javax.sdp.*;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.address.SipURI;
import javax.sip.header.CallIdHeader;
import javax.sip.header.FromHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicReference;

/**
 * SIP命令类型： INVITE请求
 */
@SuppressWarnings("rawtypes")
@Component
public class InviteRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
   private final static  SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
    private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);


    @Autowired
    Cache<String, Object> caffeineCache;

    private String method = "INVITE";

    @Autowired
    private SIPCommander sipCommander;
    @Autowired
    private HttpUtil httpUtil;

    @Autowired
    private SIPProcessorObserver sipProcessorObserver;

    @Autowired
    private SipDevice sipDevice;

    @Autowired
    private SipSubscribe sipSubscribe;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 添加消息处理的订阅
        sipProcessorObserver.addRequestProcessor(method, this);
    }

    /**
     * 处理invite请求
     *
     * @param evt 请求消息
     */
    @Override
    public void process(RequestEvent evt) {
        //Invite Request消息实现，请求视频指令
        try {
            Request request = evt.getRequest();
            SipURI sipURI = (SipURI) request.getRequestURI();
            String channelId = sipURI.getUser();
            String requesterId = null;
            FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
            AddressImpl address = (AddressImpl) fromHeader.getAddress();
            SipUri uri = (SipUri) address.getURI();
            requesterId = uri.getUser();
            if (requesterId == null || channelId == null) {
                logger.info("无法从FromHeader的Address中获取到平台id，返回400");
                responseAck(evt, Response.BAD_REQUEST); // 参数不全， 发400，请求错误
                return;
            }
            logger.info("收到平台" + requesterId + "的实时视频Invite请求");
            //responseAck(evt, Response.TRYING);
            String contentString = new String(request.getRawContent());
            // jainSip不支持y=字段， 移除移除以解析。
            String substring = contentString;
            String ssrc = "0000000404";
            int ssrcIndex = contentString.indexOf("y=");
            if (ssrcIndex > 0) {
                substring = contentString.substring(0, ssrcIndex);
                ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
            }
            ssrcIndex = substring.indexOf("f=");
            if (ssrcIndex > 0) {
                substring = contentString.substring(0, ssrcIndex);
            }
            SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
            //  获取支持的格式
            Vector mediaDescriptions = sdp.getMediaDescriptions(true);
            int port = -1;
            for (int i = 0; i < mediaDescriptions.size(); i++) {
                MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
                Media media = mediaDescription.getMedia();
                Vector mediaFormats = media.getMediaFormats(false);
                if (mediaFormats.contains("98")) {
                    port = media.getMediaPort();
                    break;
                }
            }
            if (port == -1) {
                logger.info("不支持的媒体格式，返回415");
                responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式，发415
                return;
            }
            String s = sdp.getSessionName().getValue();
            SendRtpItem sendRtpItem = new SendRtpItem();
            if (StringUtils.equals(s, "Play")){
                sendRtpItem.setType("Play");
            }
            //回放或下载请求
           else if (StringUtils.equals(s, "Playback") || StringUtils.equals(s,"Download")) {
                TimeDescriptionImpl timeDescription = (TimeDescriptionImpl) (sdp.getTimeDescriptions(true).get(0));
                TimeField timeField = (TimeField) (timeDescription.getTime());
                Date start = new Date(timeField.getStartTime() * 1000);
                Date end = new Date(timeField.getStopTime() * 1000);
                Date now = new Date();
                if (start.after(now) || end.before(now)) {
                    logger.info("时间t不正确");
                    responseAck(evt, Response.BAD_REQUEST);
                    return;
                }
                String startTime = sdf.format(start);
                String endTime = sdf.format(end);
                sendRtpItem.setStartTime(startTime);
                sendRtpItem.setEndTime(endTime);
                sendRtpItem.setType("Playback");
            }
            String username = sdp.getOrigin().getUsername();
            String addressStr = sdp.getOrigin().getAddress();
            logger.info("设备{}请求语音流，地址：{}:{}，ssrc：{}", username, addressStr, port, ssrc);
            sendRtpItem.setIp(addressStr);
            sendRtpItem.setPort(port);
            sendRtpItem.setDeviceId(channelId);
            CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
            sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
                Object vehicleInfo = caffeineCache.getIfPresent(sendRtpItem.getDeviceId());
                if (vehicleInfo==null){
                    logger.info("未找到该设备信息");
                    return;
                }
                String[] vehicle =vehicleInfo.toString().split("_") ;
                if (sendRtpItem.getType().equals("Playback")|| sendRtpItem.getType().equals("Download")){
                    int result=httpUtil.pushBackPlayStream(sendRtpItem.getIp(), sendRtpItem.getPort(), vehicle[0], Integer.parseInt(vehicle[1]), 1, 0,
                            sendRtpItem.getStartTime(),sendRtpItem.getEndTime());
                    if (result==-1){
                        logger.info("该回放时间段视频已经在播放,无需手动");
                    }else if(result==0){
                        logger.info("回放视频指令下发失败,请检查指令网关");
                    }else if(result==1){
                        logger.info("回放视频指令下发成功");
                    }else{
                        logger.info("回放视频指令下发成功,设备没有上传视频流");
                    }
                }else{
                    int result=httpUtil.pushRealTimeStream(sendRtpItem.getIp(), sendRtpItem.getPort(), vehicle[0], Integer.parseInt(vehicle[1]), 1, 0);
                    if (result==-1){
                        logger.info("实时视频已经播放,请勿重复下发指令");
                    }else if(result==0){
                        logger.info("实时视频指令下发失败,请检查指令网关");
                    }else if(result==1){
                        logger.info("实时视频指令下发成功");
                    }else{
                        logger.info("实时视频指令指令下发成功,设备没有上传视频流");
                    }
                }
            });

            sipSubscribe.addByeSubscribe(callIdHeader.getCallId(), eventResult ->{
                String vehicleInfo = caffeineCache.getIfPresent(sendRtpItem.getDeviceId()).toString();
                if (vehicleInfo==null){
                    logger.info("各位找到该设备信息");
                    return;
                }
                String[] vehicle = vehicleInfo.split("_");
                if (sendRtpItem.getType().equals("Playback")|| sendRtpItem.getType().equals("Download")){
                    int result = httpUtil.closeBackPlayStream(vehicle[0], Integer.parseInt(vehicle[1]), 1, 0,
                            sendRtpItem.getStartTime(), sendRtpItem.getEndTime());
                    if (result==1){
                        responseAck(evt, Response.OK);
                    }else{
                        responseAck(evt, Response.BUSY_HERE,"视频已经关闭,无需手动");
                    }
                }else{
                    int result = httpUtil.closeRealTimeStream(vehicle[0], Integer.parseInt(vehicle[1]), 1, 0);
                    if (result==1){
                        responseAck(evt, Response.OK);
                    }else{
                        responseAck(evt, Response.BUSY_HERE,"视频已经关闭,无需手动");
                    }
                }

            });


            String content = xml.setInviteEnd(channelId, addressStr,
                    sipDevice.getName(), sendRtpItem.getPort(), ssrc);
            responseAck(evt, content);
        } catch (SipException | InvalidArgumentException | ParseException | SdpException e) {
            logger.warn("sdp解析错误");
            e.printStackTrace();
        }
    }
}
